package utils

import (
	"errors"
	"fmt"
	"go.mongodb.org/mongo-driver/bson"
	"go.mongodb.org/mongo-driver/bson/primitive"
	"math"
	"reflect"
	"strconv"
	"strings"
	"time"
)

type Resolve struct {
	bson bson.M
}

func NewResolve(bson bson.M) *Resolve {
	return &Resolve{
		bson: bson,
	}
}

func (this *Resolve) T(key string) interface{} {

	return this.bson[key]
}

func (this *Resolve) ObjectID(key string) primitive.ObjectID {
	if this.bson[key] == nil {
		return primitive.ObjectID{}
	}
	if v, ok := this.bson[key].(primitive.ObjectID); ok {
		return v
	}
	return primitive.ObjectID{}
}

func (this *Resolve) Int(key string, defaultValue int) int {
	if this.bson[key] == nil {
		return defaultValue
	}
	/*vValue := reflect.ValueOf(this.bson[key])
	if vValue.Kind().String() == "int" {
		return this.bson[key].(int)
	}*/
	if v, ok := this.bson[key].(int); ok {
		return v
	}
	vStr := fmt.Sprintf("%v", this.bson[key])
	if i, err := strconv.Atoi(vStr); err == nil {
		return i

	}
	return defaultValue

}

func (this *Resolve) Int16(key string, defaultValue int16) int16 {
	if this.bson[key] == nil {
		return defaultValue
	}
	/*vValue := reflect.ValueOf(this.bson[key])
	if vValue.Kind().String() == "int16" {
		return this.bson[key].(int16)
	}*/
	if v, ok := this.bson[key].(int16); ok {
		return v
	}
	vStr := fmt.Sprintf("%v", this.bson[key])
	strArr := strings.Split(vStr, "e+")
	if len(strArr) == 2 {
		i0, err0 := strconv.ParseFloat(strArr[0], 64)
		i1, err1 := strconv.ParseFloat(strArr[1], 64)
		if err1 == nil && err0 == nil {
			newValue := i0 * math.Pow10(int(i1))
			return int16(newValue)
		}
	}
	if i, err := strconv.ParseInt(vStr, 10, 64); err == nil {
		return int16(i)

	}
	return defaultValue
}

func (this *Resolve) Int32(key string, defaultValue int32) int32 {
	if this.bson[key] == nil {
		return defaultValue
	}
	/*vValue := reflect.ValueOf(this.bson[key])
	if vValue.Kind().String() == "int32" {
		return this.bson[key].(int32)
	}*/
	if v, ok := this.bson[key].(int32); ok {
		return v
	}
	vStr := fmt.Sprintf("%v", this.bson[key])
	strArr := strings.Split(vStr, "e+")
	if len(strArr) == 2 {
		i0, err0 := strconv.ParseFloat(strArr[0], 64)
		i1, err1 := strconv.ParseFloat(strArr[1], 64)
		if err1 == nil && err0 == nil {
			newValue := i0 * math.Pow10(int(i1))
			return int32(newValue)
		}
	}
	if i, err := strconv.ParseInt(vStr, 10, 64); err == nil {
		return int32(i)

	}
	return defaultValue
}

func (this *Resolve) Int64(key string, defaultValue int64) int64 {
	if this.bson[key] == nil {
		return defaultValue
	}
	/*vValue := reflect.ValueOf(this.bson[key])
	if vValue.Kind().String() == "int64" {
		return this.bson[key].(int64)
	}*/
	if v, ok := this.bson[key].(int64); ok {
		return v
	}
	//
	vStr := fmt.Sprintf("%v", this.bson[key])
	strArr := strings.Split(vStr, "e+")
	if len(strArr) == 2 {
		i0, err0 := strconv.ParseFloat(strArr[0], 64)
		i1, err1 := strconv.ParseFloat(strArr[1], 64)
		if err1 == nil && err0 == nil {
			newValue := i0 * math.Pow10(int(i1))
			return int64(newValue)
		}
	}
	//
	if i, err := strconv.ParseInt(vStr, 10, 64); err == nil {
		return int64(i)
	}
	return defaultValue
}

func (this *Resolve) Float32(key string, defaultValue float32) float32 {
	if this.bson[key] == nil {
		return defaultValue
	}
	/*vValue := reflect.ValueOf(this.bson[key])
	if vValue.Kind().String() == "float64" {
		return this.bson[key].(float32)
	}*/
	if v, ok := this.bson[key].(float32); ok {
		return v
	}
	vStr := fmt.Sprintf("%v", this.bson[key])
	strArr := strings.Split(vStr, "e+")
	if len(strArr) == 2 {
		i0, err0 := strconv.ParseFloat(strArr[0], 64)
		i1, err1 := strconv.ParseFloat(strArr[1], 64)
		if err1 == nil && err0 == nil {
			newValue := i0 * math.Pow10(int(i1))
			return float32(newValue)
		}
	}
	if i, err := strconv.ParseFloat(vStr, 64); err == nil {
		return float32(i)
	}
	return defaultValue
}

func (this *Resolve) Float64(key string, defaultValue float64) float64 {
	if this.bson[key] == nil {
		return defaultValue
	}
	/*vValue := reflect.ValueOf(this.bson[key])
	if vValue.Kind().String() == "float64" {
		return this.bson[key].(float64)
	}*/
	if v, ok := this.bson[key].(float64); ok {
		return v
	}
	vStr := fmt.Sprintf("%v", this.bson[key])
	strArr := strings.Split(vStr, "e+")
	if len(strArr) == 2 {
		i0, err0 := strconv.ParseFloat(strArr[0], 64)
		i1, err1 := strconv.ParseFloat(strArr[1], 64)
		if err1 == nil && err0 == nil {
			newValue := i0 * math.Pow10(int(i1))
			return float64(newValue)
		}
	}
	if i, err := strconv.ParseFloat(vStr, 64); err == nil {
		return float64(i)
	}
	return defaultValue
}

func (this *Resolve) String(key string, defaultValue string) string {
	if this.bson[key] == nil {
		return defaultValue
	}
	if v, ok := this.bson[key].(string); ok {
		return v
	}
	return fmt.Sprintf("%v", this.bson[key])
}

func (this *Resolve) Bool(key string, defaultValue bool) bool {
	if this.bson[key] == nil {
		return defaultValue
	}
	if v, ok := this.bson[key].(bool); ok {
		return v
	}
	vStr := fmt.Sprintf("%v", this.bson[key])
	if b, err := strconv.ParseBool(vStr); err == nil {
		return b
	}
	return defaultValue
}

func (this *Resolve) Slice(key string) []bson.M {

	if this.bson[key] == nil {
		return []bson.M{}
	}
	if aValue, ok := this.bson[key].(bson.A); ok {
		var mValueArr []bson.M
		for _, item := range aValue {
			if v, ok := item.(bson.M); ok {
				mValueArr = append(mValueArr, v)
			}

		}
		return mValueArr
	}
	return []bson.M{}
}
func (this *Resolve) SliceForString(key string) []string {

	if this.bson[key] == nil {
		return []string{}
	}
	if aValue, ok := this.bson[key].([]string); ok {
		var mValueArr []string
		for _, item := range aValue {
			mValueArr = append(mValueArr, item)
		}
		return mValueArr
	}
	return []string{}
}
func TypeConversion(value interface{}, ntype string) (reflect.Value, error) {
	vValue := reflect.ValueOf(value)
	if vValue.Kind().String() == ntype && vValue.Kind().String() != "slice" {
		return vValue, nil
	}
	vStr := fmt.Sprintf("%v", value)
	if ntype == "string" {
		return reflect.ValueOf(vStr), nil
	} else if ntype == "time.Time" {
		t, err := time.ParseInLocation("2006-01-02 15:04:05", vStr, time.Local)
		return reflect.ValueOf(t), err
	} else if ntype == "Time" {
		t, err := time.ParseInLocation("2006-01-02 15:04:05", vStr, time.Local)
		return reflect.ValueOf(t), err
	} else if ntype == "int" {
		i, err := strconv.Atoi(vStr)
		return reflect.ValueOf(i), err
	} else if ntype == "int8" {
		i, err := strconv.ParseInt(vStr, 10, 64)
		return reflect.ValueOf(int8(i)), err
	} else if ntype == "int32" {
		i, err := strconv.ParseInt(vStr, 10, 64)
		return reflect.ValueOf(int64(i)), err
	} else if ntype == "int64" {
		i, err := strconv.ParseInt(vStr, 10, 64)
		return reflect.ValueOf(i), err
	} else if ntype == "float32" {
		i, err := strconv.ParseFloat(vStr, 64)
		return reflect.ValueOf(float32(i)), err
	} else if ntype == "float64" {
		i, err := strconv.ParseFloat(vStr, 64)
		return reflect.ValueOf(i), err
	}

	// else if .......增加其他一些类型的转换

	return reflect.ValueOf(value), errors.New("未知的类型：" + ntype)
}
